#include "Parser.h"

char delimiters[] = {
	',',
	'=',
	'(',
	')',
	'[',
	']',
	':',
};

struct _rsv_word{
	char name[256];
	u64 op_type;
};

enum OP_TYPE{
	OP_DONE = 0,
	OP_NOP,
	OP_VAR_DECLARE,
	OP_FUNC_DECLARE,
	
	OP_ARG_DECLARED,

	OP_CONST_INT,
	OP_CONST_FLOAT,
	OP_CONST_STR,

	OP_CONST_VARNAME,
};

_rsv_word reserved[] = {
	{"var", OP_VAR_DECLARE},	
	{"func", OP_FUNC_DECLARE},
};

std::string Parser::despaceLine(std::string line){
	char *str = (char*)line.c_str();
	for(u32 i = 0; i < strlen(str); i++){
		if(*str == ' ' || *str == '\t' || *str == '\n' || *str == '\r'){
			str++;
		}else{
			break;
		}
	}

	for(u32 i = strlen(str)-1; i >= 0; i--){
		if(str[i] == ' ' || str[i] == '\t' || str[i] == '\n' || str[i] == '\r'){
			str[i] = '\0';
		}else{
			break;
		}
	}

	std::string line = str;
	return line;
}

u32 Parser::findFirstOf(std::string line, char ch){
	int pos = 0;
	int eq = line.find_first_of(ch);

	while(eq >= 0){
		pos = line.find_first_of('"', pos);
		int pos2 = line.find_first_of('"', pos+1);

		if(pos > eq || pos < 0)
			return eq;
		else if(pos < eq && eq < pos2)
			eq = line.find_first_of('=', pos2);

		pos = pos2 + 1;
	}

	return -1;
}

bool Parser::isDelimiter(char ch){
	for(u32 i = 0; i < sizeof(delimiters); i++){
		if(delimiters[i] == ch){
			return true;
		}
	}

	return false;
}

u64 Parser::isReserved(std::string line){
	for(u32 i = 0; i < sizeof(reserved)/sizeof(_rsv_word); i++){
		if(strncmp(line.c_str(), reserved[i].name, strlen(reserved[i].name)) == 0){
			return reserved[i].op_type;
		}
	}

	return PARSER_FAIL;
}

u64 Parser::isConstant(std::string line){
	u64 ret = OP_CONST_INT;

	if(line[0] == '"' && line[line.length()-1] == '"')
		return OP_CONST_STR;
	else{
		for(u32 i = 0; i < line.length(); i++){
			if(line[i] == '.' && ret != OP_CONST_FLOAT){
				ret = OP_CONST_FLOAT;
			}else if(line[i] == '.'){
				return PARSER_FAIL;
			}else if(line[0] < '0' || line[0] > '9'){
				return PARSER_FAIL;
			}
		}
	}

	return ret;
}

u64 Parser::isVarName(std::string line){
	if((tolower(line[0]) < 'a' || tolower(line[0]) > 'z') && line[0] != '_')
		return PARSER_FAIL;

	for(u32 i = 1; i < line.length(); i++){
		if((tolower(line[i]) < 'a' || tolower(line[i]) > 'z') && (line[i] < '0' || line[i] > '9') && line[i] != '_'){
			return PARSER_FAIL;
		}
	}

	return OP_CONST_VARNAME;
}

bool Parser::checkErrors(std::vector<parser_ret> *actionList){
	for(int i = 0; i < (*actionList).size(); i++){
		if((*actionList)[i].retOpcode == OP_NOP)
		{
			return true;
		}
	}

	return false;
}

void Parser::loadTo(u8 dest, u64 org, u8 immediate){
	if(((org & 0xFF0000) >> 16) <= 0){
		code.setOpcode(LOAD);
		code.setImmediate(immediate);
		code.setRegister(0, dest); //dest register
		code.maskBytes(org, 2);
		code.endInstruction();
	}else if(((org & 0xFF00000000) >> 32) <= 0){
		code.setOpcode(LOAD);
		code.setImmediate(immediate);
		code.setRegister(0, dest); //dest register
		code.maskBytes(org >> 16, 2);
		code.endInstruction();

		code.setOpcode(ROTL);
		code.setImmediate(immediate);
		code.setRegister(0, dest); //dest register
		code.maskBytes(16, 1);
		code.endInstruction();

		code.setOpcode(NOT);
		code.setImmediate(immediate);
		code.setRegister(0, dest); //dest register
		code.maskBytes(org & 0xFFFF, 2);
		code.endInstruction();
	}else{
		code.setOpcode(LOAD);
		code.setImmediate(immediate);
		code.setRegister(0, dest); //dest register
		code.maskBytes((org & 0xFFFF000000000000) >> 48, 2);
		code.endInstruction();

		code.setOpcode(ROTL);
		code.setImmediate(immediate);
		code.setRegister(0, dest); //dest register
		code.maskBytes(48, 1);
		code.endInstruction();

		code.setOpcode(NOT);
		code.setImmediate(immediate);
		code.setRegister(0, dest); //dest register
		code.maskBytes((org & 0xFFFF00000000) >> 32, 2);
		code.endInstruction();

		code.setOpcode(ROTL);
		code.setImmediate(immediate);
		code.setRegister(0, dest); //dest register
		code.maskBytes(32, 1);
		code.endInstruction();

		code.setOpcode(NOT);
		code.setImmediate(immediate);
		code.setRegister(0, dest); //dest register
		code.maskBytes((org & 0xFFFF0000) >> 16, 2);
		code.endInstruction();

		code.setOpcode(ROTL);
		code.setImmediate(immediate);
		code.setRegister(0, dest); //dest register
		code.maskBytes(16, 1);
		code.endInstruction();

		code.setOpcode(NOT);
		code.setImmediate(immediate);
		code.setRegister(0, dest); //dest register
		code.maskBytes(org & 0xFFFF, 2);
		code.endInstruction();
	}
}

std::vector<Parser::parser_ret> Parser::parseLine(std::string line){
	parser_ret _ret = {0};
	std::vector<parser_ret> ret;

	line = despaceLine(line);

	if(line.length() <= 0){
		ret.push_back(_ret);
		return ret;
	}

	//printf("PARSING: %s\n", line.c_str());

	int pos = -1;
		
	char oldDelimiter[2] = {0};
	char tempDelimiter[2] = {0};

	char usedDelimiter = 0;
	for(int i = 0; i < line.length(); i++){
		if(isDelimiter(line[i]) || line[i] == ' ' || line[i] == '\t'){

			int n = i;
			while(line[n] == ' ' || line[n] == '\t')
				n++;
			if(isDelimiter(line[n]))
				i = n;

			oldDelimiter[0] = tempDelimiter[0];
			oldDelimiter[1] = tempDelimiter[1];

			tempDelimiter[0] = line[i];
			tempDelimiter[1] = i;
				
			if((tempDelimiter[0] == ',' && oldDelimiter[0] == ' ') || (tempDelimiter[0] == '=' && oldDelimiter[0] == ' ')){ //PREFERENCIAS
				usedDelimiter = tempDelimiter[0];
				pos = tempDelimiter[1];
				break;
			}else if(oldDelimiter[0] != 0){
				usedDelimiter = oldDelimiter[0];
				pos = oldDelimiter[1];
				break;
			}
		}
	}

	if(pos < 0 && tempDelimiter[0] == 0)
		goto end_next;
	else if(usedDelimiter == 0){
		usedDelimiter = tempDelimiter[0];
		pos = tempDelimiter[1];
	}

	if(usedDelimiter == '='){
		std::vector<parser_ret> varAddr = parseLine(line.substr(0, pos));
		std::vector<parser_ret> valAddr = parseLine(line.substr(pos+1));
		
		if(checkErrors(&varAddr))
			return varAddr;

		if(checkErrors(&valAddr))
			return valAddr;
				
		if(varAddr[varAddr.size() - 1].retOpcode != OP_ARG_DECLARED){
			_ret.retOpcode = OP_NOP;
			_ret.retArg1 = ERROR_VARIABLE_NOT_FOUND;

			ret.push_back(_ret);

			return ret;
		}

		loadTo(0x0, varAddr[varAddr.size() - 1].retArg0, 1);

		if(valAddr[0].retOpcode >= OP_CONST_INT && valAddr[0].retOpcode <= OP_CONST_STR){
			loadTo(0x1, valAddr[0].retArg0, 1);
		}else{
			//LOAD TO R1 VAR2 VALUE
		}

		code.setOpcode(LOAD);
		code.setRegister(0x0, 0);
		code.setRegister(0x1, 1);
		code.endInstruction();
		
		printf("Var %llX set to %llX\n", varAddr[varAddr.size() - 1].retArg0, valAddr[0].retArg0);

		valAddr.push_back(_ret);

		for(int i = 0; i < valAddr.size(); i++)
			varAddr.push_back(valAddr[i]);

		return varAddr;
	}else{		
		std::string parsed2 = "[";

		while(isDelimiter(parsed2[0])){
			parsed2 = line.substr(pos+1);
			parsed2 = despaceLine(parsed2);
			pos = findFirstOf(line, usedDelimiter);
		}
		
		if(isDelimiter(parsed2[0]))
			goto end_next;

		std::string parsed1 = line.substr(0, pos);
		parsed2 = line.substr(pos+1);

		if(isDelimiter(parsed2[parsed2.length()-1]))
			parsed2 = parsed2.substr(0, parsed2.length()-1);

		std::vector<parser_ret> ACTION1 = parseLine(parsed1);
		
		/*
		printf("------------\n");
		printf("LIST A: \n");
		for(int i = 0; i < ACTION1.size(); i++){
			printf("%lX :: %lX %lX\n", ACTION1[i].retOpcode, ACTION1[i].retArg0, ACTION1[i].retArg1);
			printf("%s :: %s\n\n", despaceLine(parsed1).c_str(), despaceLine(parsed2).c_str());
		}
		
		printf("------------\n");
		printf("LIST B: \n");
		for(int i = 0; i < ACTION2.size(); i++){
			printf("%lX :: %lX %lX\n", ACTION2[i].retOpcode, ACTION2[i].retArg0, ACTION2[i].retArg1);
			printf("%s :: %s\n\n", despaceLine(parsed1).c_str(), despaceLine(parsed2).c_str());
		}		
		*/

		if(checkErrors(&ACTION1))
			return ACTION1;

		switch(ACTION1[ACTION1.size() - 1].retOpcode){
			case OP_VAR_DECLARE:{				
				std::vector<parser_ret> ACTION2 = parseLine(parsed2);
				
				if(checkErrors(&ACTION2))
					return ACTION2;

				//ACTION 2 = NAME
				if(ACTION2[0].retOpcode == OP_NOP || isVarName(despaceLine(parsed2).c_str()) == PARSER_FAIL){
					_ret.retOpcode = OP_NOP;
					_ret.retArg1 = ERROR_INCORRECT_NAME;
					ret.push_back(_ret);

					return ret;
				}
				
				variable var = {0};
				var.varSize = 4;
				strcpy(var.name, despaceLine(parsed2).c_str());				

				_ret = ACTION1[ACTION1.size() - 1];
				_ret.retOpcode = OP_ARG_DECLARED;

				data.setOpcode(0x00);
				_ret.retArg0 = var.offset = data.getCount();
				data.endInstruction();
				
				variables.push_back(var);

				printf("Variable: %s DECLARED\n", despaceLine(parsed2).c_str());

				ACTION1.push_back(_ret);
				return ACTION1;
			}break;

			case OP_FUNC_DECLARE:{								
				std::vector<parser_ret> ACTION2 = parseLine(parsed2);
				
				if(checkErrors(&ACTION2))
					return ACTION2;

				if(!isVarName(despaceLine(parsed2.substr(0, parsed2.find_first_of('('))).c_str())){
					_ret.retOpcode = OP_NOP;
					_ret.retArg1 = ERROR_INCORRECT_NAME;
					ret.push_back(_ret);

					return ret;
				}

				function func;
				func.offset = code.getCount();
				strcpy(func.name, despaceLine(parsed2.substr(0, parsed2.find_first_of('('))).c_str());

				//ACTION 2 = ARGS
				for(int i = 0; i < ACTION2.size(); i++){

					if(i >= ACTION2.size() - 2){
						if(ACTION2[i].retOpcode == OP_NOP){
							_ret.retOpcode = OP_NOP;
							_ret.retArg1 = ERROR_ARG_SINTAX;
							ret.push_back(_ret);

							return ret;
						}
					}

					if(ACTION2[i].retOpcode == OP_ARG_DECLARED){
						func.args.push_back(variables[variables.size() - 1 - func.args.size()]);
					}
				}

				functions.push_back(func);

				printf("Func: %s DECLARED\n", func.name);

				_ret.retOpcode = OP_DONE;
				_ret.retArg0 = func.offset; //ADDR;
				ACTION1.push_back(_ret);

				return ACTION1;
			}break;

			default:{
				std::vector<parser_ret> ACTION2 = parseLine(parsed2);

				for(int i = 0; i < ACTION2.size(); i++)
					ACTION1.push_back(ACTION2[i]);

				return ACTION1;
			}break;
		}
	}

	goto end_real;

end_next:
	if((_ret.retOpcode = isReserved(line)) != PARSER_FAIL){
		ret.push_back(_ret);
		return ret;
	}/*
	else if(isVariable(line)){

	}else if(isFunction(line)){

	}
	 */
	else if((_ret.retOpcode = isConstant(line)) != PARSER_FAIL){
		_ret.retArg0 = _atoi64(line.c_str());
		ret.push_back(_ret);

		return ret;
	}else if((_ret.retOpcode = isVarName(line)) != PARSER_FAIL){
		ret.push_back(_ret);
		
		return ret;
	}

	_ret.retOpcode = OP_NOP;
	_ret.retArg1 = ERROR_UNKNOWN_ACTION;

end_real:

	ret.push_back(_ret);
	return ret;
}

u64 Parser::parse(){
	printf("Result: %llX\n\n", parseLine("var b = 99")[3].retOpcode);
	printf("Result: %llX\n\n", parseLine("func test(var aa = 30, var cc = 99)")[1].retOpcode);

	std::vector<u32*> instruction_set = code.getInstructionSet();
	for(u32 i = 0; i < instruction_set.size(); i++){
		u32 *set = instruction_set[i];
		for(int n = 0; n < 8192; n++){
			if(set[n] == 0x00) break;

			printf("%.8X\n", set[n]);
		}
	}
	printf("\n");

	return PARSER_OK;
}
